﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data.Common;
using System.Data.OracleClient;
using System.Collections;
using System.Data;

namespace Enter.DataProxy.DbConnector
{
	/// <summary>
	/// sql语句参数集合
	/// </summary>
	public abstract class ParameterCollection : IEnumerable<DbParameter>
	{
		private List<DbParameter> _List;

		/// <summary>
		/// 获取集合中对象的个数。
		/// </summary>
		public int Count
		{
			get { return _List.Count; }
		}

		/// <summary>
		/// 获取参数对象
		/// </summary>
		/// <param name="index">指定下标,从0开始的index</param>
		/// <returns>参数对象</returns>
		public DbParameter this[int index]
		{
			get
			{
				return _List[index];
			}
		}

		/// <summary>
		/// 获取参数对象
		/// </summary>
		/// <param name="index">指定参数名称</param>
		/// <returns>参数对象</returns>
		public DbParameter this[string parameterName]
		{
			get
			{
				foreach (DbParameter dbParam in _List)
				{
					if (dbParam.ParameterName == parameterName)
						return dbParam;
				}
				return null;
			}
		}

		/// <summary>
		/// 初始化
		/// </summary>
		public ParameterCollection()
		{
			_List = new List<DbParameter>();
		}

		/// <summary>
		/// 初始化
		/// </summary>
		/// <param name="capacity">集合每次分配空间的增量大小</param>
		public ParameterCollection(int capacity)
		{
			_List = new List<DbParameter>(capacity);
		}

		#region abstract

		/// <summary>
		/// 参数名称的前缀
		/// </summary>
		public abstract string Prefix { get; }
		/// <summary>
		/// 默认的参数名称，在没有指定参数名称的时候，将以 @Param_ 开头。
		/// </summary>
		public abstract string ParamNamePrefix { get; }

		/// <summary>
		/// 创建一个参数对象
		/// </summary>
		/// <param name="name">参数名称</param>
		/// <param name="value">参数值</param>
		/// <returns>返回一个参数对象</returns>
		protected abstract DbParameter CreateParameter(string name, object value);
		/// <summary>
		/// 创建一个参数对象
		/// </summary>
		/// <param name="name">参数名称</param>
		/// <param name="suffix">参数名称的后缀（下标，人为的控制参数惟一性）</param>
		/// <param name="value">参数值</param>
		/// <returns>返回一个参数对象</returns>
		protected abstract DbParameter CreateParameter(string name, int suffix, object value);

		#endregion

		/// <summary>
		/// 向集合中添加参数值
		/// </summary>
		/// <param name="values">参数值</param>
		/// <returns>参数名称，与values中的参数值的下标一 一对应</returns>
		public string[] Fill(object[] values)
		{
			// 不需要做空判断，如果没有参数的话长度为0

			// 因为给的values只有值，没有参数无名称，所以默认情况下将参数的名称用@param0,@param1,@param2...
			IList<string> _list = new List<string>(values.Length);
			for (int i = 0; i < values.Length; i++)
			{
				string name = this.Append(ParamNamePrefix, values[i] ?? DBNull.Value, this.Count).ParameterName;
				_list.Add(name);
			}
			return _list.ToArray();
		}
		/// <summary>
		/// 向集合中添加参数值
		/// </summary>
		/// <param name="values">参数值</param>
		/// <returns>参数名称，与values中的参数值的下标一 一对应</returns>
		public string[] Fill(IList values)
		{
			if (values == null)
				throw new ArgumentNullException("values");

			// 因为给的values只有值，没有参数无名称，所以默认情况下将参数的名称用@param0,@param1,@param2...
			IList<string> _list = new List<string>(values.Count);
			for (int i = 0; i < values.Count; i++)
			{
				string name = this.Append(ParamNamePrefix, values[i] ?? DBNull.Value, this.Count).ParameterName;
				_list.Add(name);
			}
			return _list.ToArray();
		}

		#region Append

		/// <summary>
		/// 向集合中添加一个参数对象
		/// </summary>
		/// <param name="name">参数名称</param>
		/// <param name="value">参数值</param>
		/// <returns>新建在集合中的参数对象</returns>
		public DbParameter Append(string name, object value)
		{
			DbParameter param = CreateParameter(name, value);
			this._List.Add(param);
			return param;
		}

		/// <summary>
		/// 向集合中添加一个参数对象
		/// </summary>
		/// <param name="name">参数名称</param>
		/// <param name="value">参数值</param>
		/// <param name="suffix">参数名称的后缀（下标，人为的控制参数惟一性）</param>
		/// <returns>新建在集合中的参数对象</returns>
		public DbParameter Append(string name, object value, int suffix)
		{
			DbParameter param = CreateParameter(name, suffix, value);
			this._List.Add(param);
			return param;
		}

		/// <summary>
		/// 向集合中添加一个参数对象
		/// </summary>
		/// <param name="name">参数名称</param>
		/// <param name="value">参数值</param>
		/// <param name="type">参数映射至数据库中的类型</param>
		/// <returns>新建在集合中的参数对象</returns>
		public DbParameter Append(string name, object value, DbType type)
		{
			DbParameter param = CreateParameter(name, value);
			param.DbType = type;
			this._List.Add(param);
			return param;
		}

		/// <summary>
		/// 向集合中添加一个参数对象
		/// </summary>
		/// <param name="name">参数名称</param>
		/// <param name="value">参数值</param>
		/// <param name="type">参数映射至数据库中的类型</param>
		/// <param name="suffix">参数名称的后缀（下标，人为的控制参数惟一性）</param>
		/// <returns>新建在集合中的参数对象</returns>
		public DbParameter Append(string name, object value, DbType type, int suffix)
		{
			DbParameter param = CreateParameter(name, suffix, value);
			param.DbType = type;
			this._List.Add(param);
			return param;
		}

		#endregion

		public DbParameter[] ToArray()
		{
			return _List.ToArray();
		}

		#region implement

		public IEnumerator<DbParameter> GetEnumerator()
		{
			return _List.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return _List.GetEnumerator();
		}

		#endregion

		public override string ToString()
		{
			StringBuilder content = new StringBuilder("ParameterCollection");
			content.AppendLine();
			foreach (var item in _List)
			{
				content.Append(" [").Append(item.ParameterName).Append("=").Append(item.Value).AppendLine("]; ");
			}
			return content.ToString();
		}
	}

	/// <summary>
	/// (限于SqlServer使用的参数集合)
	/// </summary>
	public class SqlParameterCollection : ParameterCollection
	{
		/// <summary>
		/// 参数名称的前缀
		/// </summary>
		private static readonly string _Prefix = "@";
		/// <summary>
		/// 默认的参数名称，在没有指定参数名称的时候，将以 @Param_ 开头。
		/// </summary>
		private static readonly string _ParamNamePrefix = "@Param_";

		/// <summary>
		/// 参数名称的前缀
		/// </summary>
		public override string Prefix
		{
			get { return _Prefix; }
		}
		/// <summary>
		/// 默认的参数名称，在没有指定参数名称的时候，将以 @Param_ 开头。
		/// </summary>
		public override string ParamNamePrefix
		{
			get { return _ParamNamePrefix; }
		}

		/// <summary>
		/// 初始化
		/// </summary>
		public SqlParameterCollection()
		{ }

		/// <summary>
		/// 初始化
		/// </summary>
		/// <param name="capacity">集合每次分配空间的增量大小</param>
		public SqlParameterCollection(int capacity)
			: base(capacity)
		{ }

		/// <summary>
		/// 创建参数对象的SqlServer实现
		/// </summary>
		/// <param name="name">参数名称</param>
		/// <param name="value">参数值</param>
		/// <returns>返回一个参数对象</returns>
		protected override DbParameter CreateParameter(string name, object value)
		{
			if (name.StartsWith(Prefix))
				return new SqlParameter(name, value ?? DBNull.Value);
			else
				return new SqlParameter(Prefix + name, value ?? DBNull.Value);
		}

		/// <summary>
		/// 创建一个参数对象
		/// </summary>
		/// <param name="name">参数名称</param>
		/// <param name="suffix">参数名称的后缀（下标，人为的控制参数惟一性）</param>
		/// <param name="value">参数值</param>
		/// <returns>返回一个参数对象</returns>
		protected override DbParameter CreateParameter(string name, int suffix, object value)
		{
			if (name.StartsWith(Prefix))
				return new SqlParameter(name + suffix, value ?? DBNull.Value);
			else
				return new SqlParameter(string.Concat(Prefix, name, suffix.ToString()), value ?? DBNull.Value);
		}
	}

	/// <summary>
	/// (限于Oracle使用的参数集合)
	/// </summary>
	public class OracleParameterCollection : ParameterCollection
	{
		/// <summary>
		/// 参数名称的前缀
		/// </summary>
		private static readonly string _Prefix = ":";
		/// <summary>
		/// 默认的参数名称，在没有指定参数名称的时候，将以 @Param_ 开头。
		/// </summary>
		private static readonly string _ParamNamePrefix = ":Param_";

		/// <summary>
		/// 参数名称的前缀
		/// </summary>
		public override string Prefix
		{
			get { return _Prefix; }
		}
		/// <summary>
		/// 默认的参数名称，在没有指定参数名称的时候，将以 @Param_ 开头。
		/// </summary>
		public override string ParamNamePrefix
		{
			get { return _ParamNamePrefix; }
		}

		/// <summary>
		/// 初始化
		/// </summary>
		public OracleParameterCollection()
		{ }

		/// <summary>
		/// 初始化
		/// </summary>
		/// <param name="capacity">集合每次分配空间的增量大小</param>
		public OracleParameterCollection(int capacity)
			: base(capacity)
		{ }

		/// <summary>
		/// 创建参数对象的Oracle实现
		/// </summary>
		/// <param name="name">参数名称</param>
		/// <param name="value">参数值</param>
		/// <returns>返回一个参数对象</returns>
		protected override DbParameter CreateParameter(string name, object value)
		{
			if (name.StartsWith(Prefix))
				return new OracleParameter(name, value);
			else
				return new OracleParameter(Prefix + name, value ?? DBNull.Value);
		}

		/// <summary>
		/// 创建一个参数对象
		/// </summary>
		/// <param name="name">参数名称</param>
		/// <param name="suffix">参数名称的后缀（下标，人为的控制参数惟一性）</param>
		/// <param name="value">参数值</param>
		/// <returns>返回一个参数对象</returns>
		protected override DbParameter CreateParameter(string name, int suffix, object value)
		{
			if (name.StartsWith(Prefix))
				return new SqlParameter(name + suffix, value ?? DBNull.Value);
			else
				return new SqlParameter(string.Concat(Prefix, name, suffix.ToString()), value ?? DBNull.Value);
		}
	}
}
